// Copyright (C) 2010 Félix Cloutier.

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License 2.0 for more details.

// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/

#ifndef JIT_RUNTIME_SYMBOLS
#define JIT_RUNTIME_SYMBOLS

#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/Module.h>
#include <llvm/Function.h>
#include <map>

#include "Common.h"

namespace LLVMJit
{

// The JitBindings class allows different components to register functions to be
//	available to the JIT compiled code. It's created by the JitExecutor and
//	passed along to the JitRecompiler by the Jit.

// Hopefully, this passing around will be a temporary hack. The JitRecompiler
//	currently needs it because it needs to bind calls to the interpreter
//	since our implementation is not complete. In a perfect world, we'd
//	recompile every single instruction.

// This sucks, because in our aforementioned perfect world, objects are
//	completely initailized after their constructor returns; but right now,
//	because JitExecutor depends on JitRecompiler which would depend on
//	JitBindings, which depends on JitExecutor, we have to partially initialize
//	JitRecompiler, then pass it the JitBindings we create later.
class JitBindings
{
public:
	enum NamedBinding
	{
		YieldMaybe,
		Yield,
		SetExpectedNPC,
		RunStub,
		Break,
		InvalidateInstructionCache
	};

private:
	llvm::ExecutionEngine* engine;
	llvm::Module* module;
	std::map<void*, llvm::Function*> bindings;
	std::map<NamedBinding, llvm::Function*> namedBindings;
	
public:
	JitBindings(llvm::ExecutionEngine* engine, llvm::Module* module);
	
	llvm::Function* GetBinding(void* address);
	llvm::Function* GetBinding(NamedBinding service);
	void Bind(llvm::Function* llvmStub, void* address);
	void Bind(llvm::Function* llvmStub, void* address, NamedBinding service);
};

}

#endif